using MongoDB.Driver;
using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.Synchronization.Interface;
using Sustainalytics.ClientDW.Synchronization.SyncESGData.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Sustainalytics.ClientDW.Synchronization.SyncESGData.CorporateDataLogic
{
    public class EsgCompaniesIdsQuery : ICoreEsgCompaniesIdsQuery, IComprehensiveEsgCompaniesIdsQuery
    {
        private readonly IMongoCollection<CompanyProfileResearchState> researchStateCollection;
        private readonly ILogger logger;

        public EsgCompaniesIdsQuery(IMongoCollection<CompanyProfileResearchState> researchStateCollection, ILogger logger)
        {
            this.researchStateCollection = researchStateCollection;
            this.logger = logger;
        }

        async Task<EsgCompaniesIds> ICoreEsgCompaniesIdsQuery.GetAsync()
        {
            var companiesWithEsgStates = await GetEsgResearchStatesAsync().ConfigureAwait(false);

            return new EsgCompaniesIds
            {
                CompaniesWithActiveResearch = companiesWithEsgStates.Where(x => x.CoreResearchState == ResearchState.ResearchAvailable).Select(x => x.CompanyId).ToList(),
                InvalidatedCompanies = companiesWithEsgStates.Where(x => x.ComprehensiveResearchState != ResearchState.ResearchAvailable || x.CoreResearchState == ResearchState.ResearchAvailable).Select(x => x.CompanyId).ToList()
            };
        }

        async Task<EsgCompaniesIds> IComprehensiveEsgCompaniesIdsQuery.GetAsync()
        {
            var companiesWithEsgStates = await GetEsgResearchStatesAsync().ConfigureAwait(false);

            return new EsgCompaniesIds
            {
                CompaniesWithActiveResearch = companiesWithEsgStates.Where(x => x.ComprehensiveResearchState == ResearchState.ResearchAvailable).Select(x => x.CompanyId).ToList(),
                InvalidatedCompanies = companiesWithEsgStates.Where(x => x.CoreResearchState != ResearchState.ResearchAvailable || x.ComprehensiveResearchState == ResearchState.ResearchAvailable).Select(x => x.CompanyId).ToList()
            };
        }

        private async Task<List<ESGCompanyProfileResearchState>> GetEsgResearchStatesAsync()
        {
            var stopWatch = Stopwatch.StartNew();

            var esgResearchStates = await researchStateCollection.Find(_ => true)
                .Project(x => new ESGCompanyProfileResearchState(x.Id, x.CoreEsgResearchState.ResearchState, x.ComprehensiveEsgResearchState.ResearchState))
                .ToListAsync().ConfigureAwait(false);

            logger.Log($"{esgResearchStates.Count} companies counted for " + $"{new StackFrame(1).GetMethod().Name} in " + $"{typeof(CompanyProfileResearchState).Name} (duration {stopWatch.Elapsed}");

            return esgResearchStates;
        }

        private struct ESGCompanyProfileResearchState
        {
            public Guid CompanyId { get; set; }

            public ResearchState ComprehensiveResearchState { get; set; }

            public ResearchState CoreResearchState { get; set; }

            public ESGCompanyProfileResearchState(Guid companyId, ResearchState coreResearchState, ResearchState comprehensiveResearchState)
            {
                CompanyId = companyId;
                ComprehensiveResearchState = comprehensiveResearchState;
                CoreResearchState = coreResearchState;
            }
        }
    }
}
